package net.droiding.server.provisioning;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.droiding.server.dao.Dao;
import net.droiding.server.pojo.Provider;
import net.droiding.server.pojo.ProviderKey;
import net.droiding.server.pojo.Station;
import net.droiding.server.pojo.StationData;
import electric.xml.Document;
import electric.xml.Element;

public class DroidingServlet extends HttpServlet {

	private Dao dao = new Dao();
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		throw new ServletException("Method not allowed: GET");
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		String action = req.getParameter("action");
		String lastUpdate = req.getParameter("last_update");
		String providerKey = req.getParameter("provider_key");
		String username = req.getParameter("username");
		String passwd = req.getParameter("passwd");
		
		Document doc = null;
		
		String current_user = (String)req.getSession().getAttribute("current_user");
		
		
		if (action != null && !"".equals(action)) {
			if ("login".equals(action) || current_user == null) {
				try {
					doc = login(username, passwd);
				} catch (Throwable t) {
					doc = generateErrorDoc(t);
					resp.setContentType("text/xml");
					doc.write(resp.getOutputStream());
					return;
					
				}
				if ("login".equals(action)) {
					resp.setContentType("text/xml");
					doc.write(resp.getOutputStream());
					return;	
				}
			}
			if ("list_providers".equals(action)) {
				
				try {
					doc = listProviders();
				} catch (Throwable t) {
					doc = generateErrorDoc(t);
				}
				resp.setContentType("text/xml");
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				doc.write(bos);
				
				resp.setContentLength(bos.size());
				resp.getOutputStream().write(bos.toByteArray());
				//doc.write(resp.getOutputStream());
				return;
			}
			if ("refresh_providers".equals(action)) {
				
				try {
					doc = refreshProviders(lastUpdate);
				} catch (Throwable t) {
					doc = generateErrorDoc(t);
				}
				resp.setContentType("text/xml");
				doc.write(resp.getOutputStream());
				return;
			}			
			if ("list_stations".equals(action)) {
				try {
					doc = listStations(providerKey);
				} catch (Throwable t) {
					doc = generateErrorDoc(t);
				}
				resp.setContentType("text/xml");
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				doc.write(bos);
				
				resp.setContentLength(bos.size());
				resp.getOutputStream().write(bos.toByteArray());
				//doc.write(resp.getOutputStream());
				return;
			}
		}
	}
	private Document listStations(String providerKey) throws Exception {
		Provider p = dao.getProviderByKey(ProviderKey.valueOf(providerKey));
		List<Station> stations = dao.getStationsByProvider(ProviderKey.valueOf(providerKey));
		Document doc = new Document();
		Element droiding = doc.setRoot("droiding");
		droiding.setAttribute("version", "1.0");
		Element providers = droiding.addElement("providers");
		Element el_prov = providers.addElement("provider");
		Element el_stations = el_prov.addElement("stations");
		populateProviderElement(el_prov, p);
		for (Station st : stations) {
			Element station = el_stations.addElement("station");
			populateStationElement(station, st);
		}
		return doc;
	}

	private Document login(String username, String passwd) throws Exception {
		dao.login(username, passwd);
		return generateLoginDoc(username);
	}

	private Document refreshProviders(String lastUpdate) throws Exception {
		List<Provider> allProviders = dao.refreshProviders(lastUpdate);
		Document doc = new Document();
		Element droiding = doc.setRoot("droiding");
		droiding.setAttribute("version", "1.0");
		Element  providers = droiding.addElement("providers");
		for (Provider p : allProviders) {
			Element e = providers.addElement("provider");
			populateProviderElement(e, p);
		}
		return doc;
	}

	private Document generateErrorDoc(Throwable t) {
		Document doc = new Document();
		Element droiding = doc.setRoot("droiding");
		droiding.setAttribute("version", "1.0");
		Element  error = droiding.addElement("error");
		error.setAttribute("type", t.getClass().getSimpleName());
		error.setAttribute("message", t.getMessage());
		return doc;
	}
	private Document generateLoginDoc(String username) {
		Document doc = new Document();
		Element droiding = doc.setRoot("droiding");
		droiding.setAttribute("version", "1.0");
		Element  login = droiding.addElement("login");
		login.setAttribute("status", "successful");
		return doc;
	}
	private Document listProviders() throws Exception {
		List<Provider> allProviders = dao.getAllProviders();
		Document doc = new Document();
		Element droiding = doc.setRoot("droiding");
		droiding.setAttribute("version", "1.0");
		Element  providers = droiding.addElement("providers");
		for (Provider p : allProviders) {
			Element e = providers.addElement("provider");
			populateProviderElement(e, p);
		}
		return doc;
	}
	private void populateProviderElement(Element e, Provider p) {
		e.setAttribute("key", p.getKey().getValue());
		e.setAttribute("name", p.getName());
		e.setAttribute("location", p.getLocation());
		e.setAttribute("lat", "" + p.getLatitude());
		e.setAttribute("lng", "" + p.getLongitude());
		e.setAttribute("zoom", "" + p.getZoomLevel());
		e.setAttribute("web", p.getWebsite());
		e.setAttribute("lastupdate", "" + p.getLastUpdate());
	}
	private void populateStationElement(Element e, Station s) {
		e.setAttribute("remoteid", "" + s.getId());
		e.setAttribute("skey", s.getKey());
		e.setAttribute("pkey", s.getProviderKey().getValue());
		e.setAttribute("name", s.getLocation());
		e.setAttribute("lat", "" + s.getLatitude());
		e.setAttribute("lng", "" + s.getLongitude());
		e.setAttribute("lastupdate", "" + s.getLastUpdate());
		if (s.getData().size() == 1) {
			StationData sd = s.getData().get(0);
			e.setAttribute("bikes", "" + sd.getBikes());
			e.setAttribute("slots", "" + sd.getSlots());
		} else {
			e.setAttribute("bikes", "0");
			e.setAttribute("slots", "0");
		}
			
		
	}
}
